package com.btcode.schedule;

import com.btcode.exception.MsgException;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.PersistJobDataAfterExecution;

/**
 * 单实例job，不是单例job<br> 区别在于，如果两个jobDetail使用同一个jobclass，那么还是会产生两个实例，但也只会产生两个<br>
 * 目的在于，让job每次都是用同一个实例，而不是new一个<br> 因为quartz是多线程的，每次执行任务，都会把Job实例化<br>
 * 这会带来一些困扰，比如读取串口数据的时候，初始化一次就可以了<br> 如果每次都初始化，必定会有问题，所以做了如下设计，希望是每次执行任务调用的都是同一个实例<br>
 * <br>
 * 继承这个类后，初始化的逻辑，都放在initJob这个方法中做，而不是写在构造函数里<br>
 *
 * 构造函数构造出来的对象，和定时任务最终执行的对象，不是同一个，所以不要直接在类里面定义变量，然后在myExecute里面使用， 要传参给这个类，使用ScheduleManager.getInstance().addJob(getClass(),cronSStr,five,deviceId);的方式
 *
 * @author gislin
 * @author gislin
 * @DisallowConcurrentExecution 注解强制任务串行
 * @PersistJobDataAfterExecution 让每个任务够共享同一套jobDetailMap数据
 */
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public abstract class SingleInstanceJob implements Job {

    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        SingleInstanceJob instance = getDriveInstance(arg0);
        instance.myExecute(arg0);
    }

    public abstract void initJob(JobExecutionContext arg0);

    public abstract void myExecute(JobExecutionContext arg0);

    private SingleInstanceJob getDriveInstance(JobExecutionContext arg0) {

        SingleInstanceJob driveInstance = null;
        JobKey jobKey = arg0.getJobDetail().getKey();
        try {
            driveInstance = JobInstanceHolder.getInstance().getJobInstance(
                arg0.getJobDetail().getKey());

            if (driveInstance == null) {
                driveInstance = this;
                driveInstance.initJob(arg0);
                JobInstanceHolder.getInstance().putJobInstance(jobKey, driveInstance);
            }
        }
        catch (Exception e) {
            throw new MsgException("获取驱动实例出错", e);
        }

        return driveInstance;
    }

}
